﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO.Ports;
using System.IO;
using System.Threading;

namespace Leaf_SerialPort_Basis
{
    public partial class Form1 : Form
    {
        public static Form1 mForm1 = null;

        Leaf_converion Lc = new Leaf_converion();

        //全局变量
        public class MyGlobal
        {
            //升级的文件相关
            public static long File_size = 0;        //升级文件的大小
            public static int ToUpdateFlag = 0;      //0 等待点击升级按钮, 1发送升级头,等待确认, 2正在升级,接收数据,
        }

        public class Receive
        {
            public static byte[] buff = new byte[2000];
            public static int len = 0;
        }

        public class Trans
        {
            public static byte[] buff = new byte[2000];
            public static int len = 0;
        }

        /* 添加参数值 */
        SerialPort hdlport = null;

        #region/* 主窗口 */
        public Form1()
        {
            InitializeComponent();
            mForm1 = this;
        }
        #endregion

        #region/* 窗口加载函数 */
        private void Form1_Load(object sender, EventArgs e)
        {
            /*居中*/
            int x = (System.Windows.Forms.SystemInformation.WorkingArea.Width / 2 - this.Size.Width / 2);
            int y = (System.Windows.Forms.SystemInformation.WorkingArea.Height / 2 - this.Size.Height / 2); 
            this.StartPosition = FormStartPosition.Manual;
            this.Location = (Point)new Size(x, y);

            /* 刷新COM口 */
            //for (int i = 0; i < 100; i++)
            //{
            //    try
            //    {
            //        SerialPort a = new SerialPort("COM" + (i + 1).ToString());
            //        a.Open();
            //        a.Close();
            //        comboBox_Port.Items.Add("COM" + (1 + i).ToString());
            //        comboBox_Port.SelectedIndex = 0;
            //    }
            //    catch (Exception)
            //    {
            //        continue;
            //    }
            //}
            string[] ArryPort = SerialPort.GetPortNames();
            comboBox_Port.Items.Clear();
            for (int i = 0; i < ArryPort.Length; i++)
            {
                comboBox_Port.Items.Add(ArryPort[i]);
            }

            /* 增加波特率 */
            comboBox_BaudRate.Items.Add("1200");
            comboBox_BaudRate.Items.Add("2400");
            comboBox_BaudRate.Items.Add("4800");
            comboBox_BaudRate.Items.Add("9600");
            comboBox_BaudRate.Items.Add("19200");
            comboBox_BaudRate.Items.Add("38400");
            comboBox_BaudRate.Items.Add("115200");
            comboBox_BaudRate.SelectedIndex = 6;

        }
        #endregion

        #region Read_File_Data 读取并且发送数据
        public void Read_File_Data(long addr, int size)
        {
            byte[] s_tmp = new byte[1024];

            /// 打开文件:读数据
            string r_path = textBox_File.Text;
            try
            {
                FileStream F = new FileStream(r_path, FileMode.OpenOrCreate, FileAccess.Read);//打开文件
                long File_len = F.Length;
                F.Position = addr;

                s_tmp[0] = (byte)'D';
                s_tmp[1] = (byte)'A';
                s_tmp[2] = (byte)'T';
                s_tmp[3] = (byte)'A';
                s_tmp[4] = (byte)((addr >> 24) & 0xFF);
                s_tmp[5] = (byte)((addr >> 16) & 0xFF);
                s_tmp[6] = (byte)((addr >> 8) & 0xFF);
                s_tmp[7] = (byte)((addr) & 0xFF);
                s_tmp[8] = (byte)size;

                /// 读取数据,并且发送
                for (int i = 0; i < size; i++)
                {
                    if (F.Position != File_len)//有数据可以读取
                    {
                        byte tmp = (byte)F.ReadByte();
                        s_tmp[i + 9] = tmp;
                    }
                    else
                    {
                        s_tmp[i + 9] = 0xFF;
                    }
                }
                
                /// 校验和
                for (int i = 0; i < (size + 9) ; i++)
                {
                    s_tmp[size + 9] += s_tmp[i];
                }
                SerialPortSendData(s_tmp, size + 10);

                F.Close();
            }
            catch{}
        }
        #endregion 

        #region /* 串口数据接收事件 */
        private void hdlport_DataReceived(object sender, SerialDataReceivedEventArgs e)//第一个串口收数据
        {

            byte[] recbuffer;
            try
            {
                recbuffer = new byte[hdlport.BytesToRead];
                hdlport.Read(recbuffer, 0, recbuffer.Length);

                for (int i = 0; i < recbuffer.Length; i++)
                {
                    Receive.buff[i] = recbuffer[i];
                }
                Receive.len = recbuffer.Length % 2000;

                DealReceive();
            }
            catch (Exception)
            {
                ;
            }
        }
        #endregion

        #region/* 串口数据发送函数 */
        public void SerialPortSendData(byte[] orderbuff, int orderbuff_len)
        {
            /* 串口打开就发送 */
            if (button_Update.Text.Trim() == "停止")
            {
                /* 检查发送的数据是否为空 */
                if (orderbuff_len == 0)
                {
                    MessageBox.Show("请确保发送数据格式正确");
                    return;
                }
                hdlport.Write(orderbuff, 0, orderbuff_len);
            }
            else
            {
                MessageBox.Show("串口出现问题");
            }
        }
        #endregion

        #region /* 串口数据接收函数 */
        private void DealReceive()
        {
            /* 校验 */
            byte sum = 0;
            for (int i = 0; i < (Receive.len - 1); i++)
            {
                sum += Receive.buff[i];
            }
            if (sum != Receive.buff[Receive.len - 1]) return;

            if (Receive.len == 10)//数据 ("DATA")+(4字节地址)+(1字节大小)+(1字节校验) = 10
            {
                if (Receive.buff[0] != 'D') return;
                if (Receive.buff[1] != 'A') return;
                if (Receive.buff[2] != 'T') return;
                if (Receive.buff[3] != 'A') return;
                long addr = (long)((Receive.buff[4] << 24) + (Receive.buff[5] << 16) + (Receive.buff[6] << 8) + Receive.buff[7]);

                // 读取并发送数据
                Read_File_Data(addr, 128);
                MyGlobal.ToUpdateFlag = 2;

            }

            if (Receive.len == 3)//结束 ("OK")+(1字节校验) = 3
            {
                if (Receive.buff[0] != 'O') return;
                if (Receive.buff[1] != 'K') return;

                //Debug:升级成功!!!
                richTextBox_debug1.Text += "> 升级成功 ! ! !";
                richTextBox_debug1.Text += "\n";
                richTextBox_debug1.Select(richTextBox_debug1.TextLength, 0);
                richTextBox_debug1.ScrollToCaret();

                button_Update.Text = "升级";
                button_Update.BackColor = System.Drawing.Color.LightBlue;
                MyGlobal.ToUpdateFlag = 0;
                hdlport.Close();
            }
            //打印接收到的数据
            //string str_receive;
            //str_receive = Lc.ToHexString(Receive.buff, orderlen);
            //richTextBox_debug1.Text = richTextBox_debug1.Text + str_receive;;
        }
        #endregion


        #region 
        private void Button_About_Click(object sender, EventArgs e)
        {
            Form_Note frm = new Form_Note();
            frm.Show();
        }
        #endregion

        #region 打开文件按钮 点击事件
        private void button_OpenFile_Click(object sender, EventArgs e)
        {
            OpenFileDialog fileName = new OpenFileDialog();
            fileName.InitialDirectory = Application.StartupPath;
            fileName.Filter = "(*.bin)|*.bin|(*.txt)|*.txt|(*.hex)|*.hex";
            fileName.FilterIndex = 0;
            fileName.RestoreDirectory = true;
            if (fileName.ShowDialog() == DialogResult.OK)
            {
                string Path = fileName.FileName.ToString();
                string Name = Path.Substring(Path.LastIndexOf("\\") + 1);
                textBox_File.Text = Path;
            }
        }
        #endregion

        #region  升级发送线程
        public void Thread_update()
        {
            //获取文件
            string r_path = textBox_File.Text;
            try
            {
                FileStream F = new FileStream(r_path, FileMode.Open, FileAccess.Read);//打开文件
                long File_len = F.Length;
                MyGlobal.File_size = File_len;
                F.Close();
            }
            catch (Exception)
            {
                //Debug:文件大小信息
                richTextBox_debug1.Text += "> 文件打开错误 ! ! !";
                richTextBox_debug1.Text += "\n";
                richTextBox_debug1.Select(richTextBox_debug1.TextLength, 0);
                richTextBox_debug1.ScrollToCaret();

                //MessageBox.Show("文件打开错误!!!");

                button_Update.Text = "升级";
                button_Update.BackColor = System.Drawing.Color.LightBlue;
                MyGlobal.ToUpdateFlag = 0;
                hdlport.Close();
                return;
            }

            //Debug:文件大小信息
            Invoke(new MethodInvoker(delegate ()
            {
                richTextBox_debug1.Text += "> File size:";
                richTextBox_debug1.Text += MyGlobal.File_size.ToString();
                richTextBox_debug1.Text += "\n";
                richTextBox_debug1.Select(richTextBox_debug1.TextLength, 0);
                richTextBox_debug1.ScrollToCaret();
            }));

            //升级命令
            byte[] tmp = new byte[10];
            tmp[0] = (byte)'S';
            tmp[1] = (byte)'T';
            tmp[2] = (byte)'A';
            tmp[3] = (byte)'R';
            tmp[4] = (byte)'T';
            tmp[5] = (byte)((MyGlobal.File_size >> 24) & (0xFF));
            tmp[6] = (byte)((MyGlobal.File_size >> 16) & (0xFF));
            tmp[7] = (byte)((MyGlobal.File_size >> 8) & (0xFF));
            tmp[8] = (byte)((MyGlobal.File_size) & (0xFF));
            tmp[9] = 0;

            /// 计算和校验
            for (int i = 0; i < 9; i++)
            {
                tmp[9] += tmp[i];
            }

            //填充数据
            int time = 0;
            while (MyGlobal.ToUpdateFlag == 1)
            {
                /// 发送命令阶段
                SerialPortSendData(tmp, 10);
                Thread.Sleep(100);

                if (time++ > 100)
                {
                    Invoke(new MethodInvoker(delegate ()
                    {
                        //Debug:升级失败!!!
                        richTextBox_debug1.Text += "> 升级失败 ! ! !";
                        richTextBox_debug1.Text += "\n";
                        richTextBox_debug1.Select(richTextBox_debug1.TextLength, 0);
                        richTextBox_debug1.ScrollToCaret();
                        //MessageBox.Show("升级失败!!!");

                        button_Update.Text = "升级";
                        button_Update.BackColor = System.Drawing.Color.LightBlue;
                        MyGlobal.ToUpdateFlag = 0;
                        hdlport.Close();
                    }));


                    return;
                }
            }

        }
        #endregion

        #region  升级按钮点击事件
        private void button_Update_Click(object sender, EventArgs e)
        {
            if (button_Update.Text.Trim() == "停止")
            {
                button_Update.Text = "升级";
                button_Update.BackColor = System.Drawing.Color.LightBlue;
                MyGlobal.ToUpdateFlag = 0;
                hdlport.Close();
            }
            else if (button_Update.Text.Trim() == "升级")
            {
                //打开串口
                hdlport = new SerialPort();
                hdlport.PortName = comboBox_Port.Text.Trim();
                hdlport.BaudRate = Convert.ToInt32(comboBox_BaudRate.Text.Trim());
                hdlport.Parity = Parity.None;
                hdlport.DataBits = 8;
                hdlport.StopBits = StopBits.One;
                hdlport.ReadTimeout = -1;
                hdlport.RtsEnable = true;
                hdlport.Open();
                hdlport.DataReceived += new SerialDataReceivedEventHandler(hdlport_DataReceived);


                button_Update.Text = "停止";
                button_Update.BackColor = System.Drawing.Color.LightGreen;

                MyGlobal.ToUpdateFlag = 1;

                // 线程相关:打开升级线程
                ThreadStart childref = new ThreadStart(Thread_update);
                Thread childThread = new Thread(childref);
                childThread.Start();
            }
        }
        #endregion

        private void comboBox_Port_DropDown(object sender, EventArgs e)
        {
            /* 刷新COM口 */
            //comboBox_Port.Items.Clear();
            //for (int i = 0; i < 100; i++)
            //{
            //    try
            //    {
            //        SerialPort a = new SerialPort("COM" + (i + 1).ToString());
            //        a.Open();
            //        a.Close();
            //        comboBox_Port.Items.Add("COM" + (1 + i).ToString());
            //    }
            //    catch (Exception)
            //    {
            //        continue;
            //    }
            //}
            string[] ArryPort = SerialPort.GetPortNames();
            comboBox_Port.Items.Clear();
            for (int i = 0; i < ArryPort.Length; i++)
            {
                comboBox_Port.Items.Add(ArryPort[i]);
            }
        }
    }
}
